package cn.lsh.cas;

import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.Filter;

import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.cas.CasFilter;
import org.apache.shiro.cas.CasSubjectFactory;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.session.SingleSignOutHttpSessionListener;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.web.filter.DelegatingFilterProxy;

/*
 * shiro集成cas配置
 */
//@Configuration
public class ShiroCasConfiguration {

    // cas server地址  
    public static final String casServerUrlPrefix = "http://127.0.0.1:8080/cas";  
    // Cas登录页面地址  
    public static final String casLoginUrl = casServerUrlPrefix + "/login";  
    // Cas登出页面地址  
    public static final String casLogoutUrl = casServerUrlPrefix + "/logout";  
    // 当前工程对外提供的服务地址  
    public static final String shiroServerUrlPrefix = "http://127.0.0.1:8081";  
    // casFilter UrlPattern  
    public static final String casFilterUrlPattern = "/cas";
    // 登录地址  
    public static final String loginUrl = casLoginUrl + "?service=" + shiroServerUrlPrefix + casFilterUrlPattern;  
    // 登出地址（casserver启用service跳转功能，需在webapps\cas\WEB-INF\cas.properties文件中启用cas.logout.followServiceRedirects=true）  
    public static final String logoutUrl = casLogoutUrl+"?service="+loginUrl;  
    // 登录成功地址  
    public static final String loginSuccessUrl = "/home";  
    // 权限认证失败跳转地址  
    public static final String unauthorizedUrl = "/error/403.html"; 
    
    
    @Bean
    public DefaultWebSecurityManager securityManager(){
    	DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    	securityManager.setRealm(shiroCasRealm());
        // 用户授权/认证信息Cache, 采用EhCache 缓存
    	securityManager.setCacheManager(getEhCacheManager());
    	//指定 SubjectFactory
    	securityManager.setSubjectFactory(new CasSubjectFactory());
    	return securityManager;
    }
    
    @Bean
    public EhCacheManager getEhCacheManager(){
    	EhCacheManager em=new EhCacheManager();
    	em.setCacheManagerConfigFile("classpath:config/ehcache-shiro.xml");
    	return em;
    }
    
    @Bean
    public ShiroCasRealm shiroCasRealm(){
    	ShiroCasRealm shiroCasRealm=new ShiroCasRealm();
    	shiroCasRealm.setCasServerUrlPrefix(casServerUrlPrefix);
    	shiroCasRealm.setCasService(shiroServerUrlPrefix+casFilterUrlPattern);
    	shiroCasRealm.setDefaultRoles("user");
    	return shiroCasRealm;
    }
    
    //配置登出的session监听器
    @Bean
//    @Order(Ordered.HIGHEST_PRECEDENCE)
    public ServletListenerRegistrationBean<?> singleSignOutHttpSessionListener(){
    	ServletListenerRegistrationBean bean=new ServletListenerRegistrationBean();
    	bean.setListener(new SingleSignOutHttpSessionListener());
    	bean.setEnabled(true);
    	return bean;
    }
    
    //配置登出的过滤器
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public FilterRegistrationBean singleSignOutFilter(){
    	FilterRegistrationBean bean=new FilterRegistrationBean();
    	bean.setName("singleSignOutFilter");
    	bean.setFilter(new SingleSignOutFilter());
    	bean.addUrlPatterns("/*");
    	bean.setEnabled(true);
    	return bean;
    }
    
    @Bean
    public FilterRegistrationBean delegatingFilterProxy(){
    	FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
    	filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));
    //  该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理  
    	filterRegistration.addInitParameter("targetFilterLifecycle","true");
    	filterRegistration.setEnabled(true);
    	filterRegistration.addUrlPatterns("/*");
    	return filterRegistration;
    }
    
    @Bean(name="lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor(){
    	return new LifecycleBeanPostProcessor();
    }
    
    @Bean
//    @DependsOn(value="LifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
    	DefaultAdvisorAutoProxyCreator advisor=new DefaultAdvisorAutoProxyCreator();
    	advisor.setProxyTargetClass(true);
    	return advisor;
    }
    
    @Bean 
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(
    		DefaultSecurityManager securityManager){
    	AuthorizationAttributeSourceAdvisor autho=new AuthorizationAttributeSourceAdvisor();
    	autho.setSecurityManager(securityManager);
    	return autho;
    }
    
    @Bean(name="casFilter")
    public CasFilter getCasFilter(){
    	CasFilter casFilter=new CasFilter();
    	casFilter.setName("casFilter");
    	casFilter.setEnabled(true);
    	casFilter.setFailureUrl(loginUrl);
    	casFilter.setLoginUrl(loginUrl);
    	return casFilter;
    }
    
    @Bean(name="shiroFilter")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultSecurityManager securityManager,
    		CasFilter casFilter){
    	ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    	shiroFilterFactoryBean.setSecurityManager(securityManager);
    	
    	shiroFilterFactoryBean.setLoginUrl(loginUrl);
    	shiroFilterFactoryBean.setUnauthorizedUrl(unauthorizedUrl);
    	
    	Map<String, Filter> filters =new LinkedHashMap<String, Filter>();
    	filters.put("casFilter", getCasFilter());
    	
    	shiroFilterFactoryBean.setFilters(filters);
    	
    	loadShiroFilterChain(shiroFilterFactoryBean);
    	
    	return shiroFilterFactoryBean;
    }
    
    private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean){
    	Map<String, String> filterChainDefinitionMap =new LinkedHashMap<String, String>();
    	// shiro集成cas后，首先添加该规则，自定义的casFilter过滤器
    	filterChainDefinitionMap.put(casFilterUrlPattern, "casFilter");
    	
        //2.不拦截的请求  
        filterChainDefinitionMap.put("/css/**","anon");  
        filterChainDefinitionMap.put("/js/**","anon");  
        filterChainDefinitionMap.put("/login.jsp", "anon");  
        // 此处将logout页面设置为anon，而不是logout，因为logout被单点处理，而不需要再被shiro的logoutFilter进行拦截  
        filterChainDefinitionMap.put("/logout","anon");  
        filterChainDefinitionMap.put("/error","anon"); 
        filterChainDefinitionMap.put("/jsp/test.jsp", "anon");
        
        //3.拦截的请求（从本地数据库获取或者从casserver获取(webservice,http等远程方式)，看你的角色权限配置在哪里）  
        filterChainDefinitionMap.put("/user", "authc"); //需要登录  
  
        //4.登录过的不拦截  
        filterChainDefinitionMap.put("/**", "authc"); 
        
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    }
}
